package hehe.container.base;

import hehe.container.scan.ScanCondition;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

/**
 * 系统路径
 * <B>说明：</B>
 * <pre>
 *  维护系统各路径
 * 支持通配符
 * 规则:加载路径中的通配符：?（匹配单个字符），*（匹配除/外任意字符）、**(匹配任意多个目录)
 *  classpath:app-Beans.xml
 *　说明：无通配符，必须完全匹配
 *
 * classpath:App?-Beans.xml
 * 说明：匹配一个字符，例如 App1-Beans.xml 、 App2-Beans.xml
 * </pre>
 * <B>示例：</B>
 * <pre>
 *  略
 * </pre>
 * <B>日志：</B>
 * <pre>
 *  略
 * </pre>
 * <B>注意事项：</B>
 * <pre>
 *  略
 * </pre>
 */
public class ResourcePath
{
    // classpath 路径,相当于src 下目录
    public static final String CLASSPATH_ALIAS = "$classpath:";

    // 容器配置文件的当前目录
    public static final String CONF_ALIAS = "$conf:";

    // web 项目路径,即当前web项目WEB-INF路径
    public static final String WEB_ALIAS = "$web:";
    // 别名起始标签
    private static final String START_TAG_ALIAS = "$";
    // 别名结束标签
    private static final String END_TAG_ALIAS = ":";

    /**
     * 路径集合
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public Map<String,String> paths = new HashMap<>();

    public ResourcePath()
    {
        this.init();
    }

    public void init()
    {
        String classpath = ResourcePath.class.getResource(File.separator).getPath();
        this.setAlias(CLASSPATH_ALIAS,classpath);
    }

    /**
     * 设置路径别名
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public void setAlias(String alias,String path)
    {
        alias = this.formatAlias(alias);

        if (path.startsWith(START_TAG_ALIAS)) {
            // 找到第一个: 位置
            int pos = path.indexOf(END_TAG_ALIAS);
            if (pos != -1) {
                String pathAlias = path.substring(0,pos);
                path = this.getAlias(pathAlias) + path.substring(pos);
            }
        }

        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }

        this.paths.put(alias,path);
    }

    /**
     * 获取路径别名
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public String getAlias(String alias)
    {
        alias = this.formatAlias(alias);

        if (this.paths.containsKey(alias)) {
            return this.paths.get(alias);
        } else {
            return "";
        }
    }

    /**
     * 获取完整路径
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public String getFullPath(String path)
    {
        String alias = this.getAliasName(path);
        if (!alias.equals("")) {
            path = path.replace(alias,this.getAlias(alias));
        }

        return path;
    }

    public String getScanFullPath(String path)
    {
        String alias = this.getAliasName(path);
        if (!alias.equals("")) {
            path = path.replace(alias,this.getAlias(alias));
        }

        return this.formatPath(path);
    }

    /**
     * 获取路径中别名名称
     *<B>说明：</B>
     *<pre>
     *  略
     *</pre>
     */
    public String getAliasName(String path)
    {
        String pathAlias = "";
        if (path.startsWith(START_TAG_ALIAS)) {
            // 找到第一个: 位置
            int pos = path.indexOf(END_TAG_ALIAS);
            if (pos != -1) {
                pathAlias = path.substring(0,pos + 1);
            }
        }

        return pathAlias;
    }

    private String formatAlias(String alias)
    {
        if (!alias.startsWith(START_TAG_ALIAS)) {
            alias = START_TAG_ALIAS + alias + END_TAG_ALIAS;
        }

        return alias;
    }

    /**
     * 格式化路径
     *<B>说明：</B>
     *<pre>
     *  通配符转换成正则表达式
     *</pre>
     */
    public String formatPath(String path)
    {

        path = path.replace(".","\\.");

        // 替换** 转换成
        path = path.replace("**","(\\w+)");

        //  将? 替换 [.*]
        path = path.replace("?","(.?)");

        // 替换* 转[.*]
        path = path.replace("*","(((?!\\" +File.separator+ ").)*)");

        return "^" + path + "$";
    }

    /**
     * 查找最靠近通配符目录
     *<B>说明：</B>
     *<pre>
     *  比如:/user/account/beans?.xml
     *  则:/user/account
     *</pre>
     */
    public String findBasePath(String path)
    {
        int twoAsteriskPos = path.indexOf("**");
        int oneAsteriskPos = path.indexOf("*");

        int pos = oneAsteriskPos;
        if (twoAsteriskPos == -1 && oneAsteriskPos == -1) {
            pos = -1;
        } else {
            if (twoAsteriskPos == -1) {
                pos = oneAsteriskPos;
            } else {
                if (twoAsteriskPos <= oneAsteriskPos) {
                    pos = twoAsteriskPos;
                }
            }
        }

        int baseDirPos;
        if (pos == -1) {
            baseDirPos = path.lastIndexOf(File.separator);
        } else {
            baseDirPos = path.substring(0,pos).lastIndexOf(File.separator);
        }

        if (baseDirPos == -1) {
            return path;
        } else {
            return  path.substring(0,baseDirPos);
        }

    }

    public ScanCondition getScanPath(String path)
    {
        String  basePath = this.findBasePath(this.getFullPath(path));
        String rule  = this.getScanFullPath(path);
        boolean readAll = false;
        if (path.indexOf("**" + File.separator) != -1) {
            readAll = true;
        }

        return new ScanCondition(basePath,rule,readAll);
    }

    public ScanCondition getScanPackage()
    {
        return null;
    }

}
